package com.zzzy.sys.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zzzy.common.exception.WarningException;
import com.zzzy.common.util.AssertUtil;
import com.zzzy.common.util.CglibBeanCopierUtil;
import com.zzzy.common.util.MyBatisUtils;
import com.zzzy.common.vo.PageResult;
import com.zzzy.framework.core.mybatis.query.LambdaQueryWrapperE;
import com.zzzy.sys.api.DeptApi;
import com.zzzy.sys.common.constant.DeptRootIdConstant;
import com.zzzy.sys.dao.entity.Dept;
import com.zzzy.sys.dao.mapper.DeptMapper;
import com.zzzy.sys.dto.DeptInfoDto;
import com.zzzy.sys.vo.DeptSelectPageReq;
import com.zzzy.sys.vo.dept.DeptAddReq;
import com.zzzy.sys.vo.dept.DeptListReq;
import com.zzzy.sys.vo.dept.DeptTreeVO;
import com.zzzy.sys.vo.dept.DeptUpdateReq;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 部门 服务实现类
 *
 * @author fc
 * @since 2024-04-22
 */
@Service
public class DeptService extends ServiceImpl<DeptMapper, Dept> implements DeptApi {

    public List<Dept> getDeptList(DeptListReq queryReq) {
        LambdaQueryWrapperE<Dept> queryWrapperE = new LambdaQueryWrapperE<Dept>()
                .likeIfPresent(Dept::getName, queryReq.getName())
                .orderByAsc(Dept::getSort);
        return baseMapper.selectList(queryWrapperE);
    }

    public void addDept(DeptAddReq addReq) {
        validateParentDept(null, addReq.getParentId());

        Dept dept = CglibBeanCopierUtil.copy(addReq, Dept.class);
        dept.setCreateTime(LocalDateTime.now());
        baseMapper.insert(dept);
    }

    public Dept getDeptById(Long id) {
        Dept dept = getById(id);
        AssertUtil.nonNull(dept, "部门不存在");
        return dept;
    }

    public void updateById(DeptUpdateReq updateReq) {
        validateParentDept(updateReq.getId(), updateReq.getParentId());
        Dept dept = getDeptById(updateReq.getId());
        CglibBeanCopierUtil.copy(updateReq, dept);
        dept.setUpdateTime(LocalDateTime.now());
        updateById(dept);
    }

    void validateParentDept(Long ownerId, Long parentId) {
        if (DeptRootIdConstant.ID.equals(parentId)) {
            return;
        }
        if (DeptRootIdConstant.ID.equals(ownerId)){
            AssertUtil.isTrue(parentId.equals(0L), "顶级公司修改错误，如有疑问请联系管理员");
            return;
        }
        if (Objects.equals(ownerId, parentId)) {
            throw new WarningException("不能设置自己为自己的上级部门");
        }
        Dept parentDept = getDeptById(parentId);
        if (Objects.isNull(parentDept)) {
            throw new WarningException("上级部门不存在");
        }
        //递归校验父部门，如果父部门是自己的子部门，则报错，避免形成环路，ownerId 为空，说明新增，不需要考虑环路
        if (Objects.isNull(ownerId)) {
            return;
        }
        while (!DeptRootIdConstant.ID.equals(parentId)){
            parentId = parentDept.getParentId();
            parentDept = getDeptById(parentId);
            if (Objects.equals(ownerId, parentId)) {
                throw new WarningException("不能设置自己的子部门为上级部门");
            }
        }
    }

    public void deleteById(Long id) {
        Dept dept = getDeptById(id);
        AssertUtil.isNotEquals(DeptRootIdConstant.ID, dept.getId(), "根部门(公司)不能删除");
        Long subDeptCount = baseMapper.selectCount(new LambdaQueryWrapper<Dept>().eq(Dept::getParentId, id));
        AssertUtil.isTrue(subDeptCount == 0, "此部门下存在子部门,请先删除子部门");
        removeById(id);
    }

    public List<DeptTreeVO> getDeptTree() {
        LambdaQueryWrapper<Dept> queryWrapperE = new LambdaQueryWrapper<Dept>()
                .orderByAsc(Dept::getParentId).orderByAsc(Dept::getSort);
        List<Dept> deptList = baseMapper.selectList(queryWrapperE);
        List<DeptTreeVO> deptTreeList = CglibBeanCopierUtil.convertList(deptList, DeptTreeVO.class);
        Map<Long, DeptTreeVO> treeNodeMap = new LinkedHashMap<>();
        deptTreeList.forEach(dept -> treeNodeMap.put(dept.getId(), dept));
        // 处理父子关系
        treeNodeMap.values().stream().filter(node -> !node.getId().equals(DeptRootIdConstant.ID)).forEach(childNode -> {
            // 获得父节点
            DeptTreeVO parentNode = treeNodeMap.get(childNode.getParentId());
            if (Objects.isNull(parentNode)) {
                throw new WarningException(childNode.getId() + " 找不到父部门");
            }
            // 将自己添加到父节点中
            if (CollectionUtils.isEmpty(parentNode.getChildren())) {
                parentNode.setChildren(new ArrayList<>());
            }
            parentNode.getChildren().add(childNode);
        });
        return treeNodeMap.values().stream().filter(node -> node.getId().equals(DeptRootIdConstant.ID)).collect(Collectors.toList());
    }

    public Dept getDeptByName(String deptName) {
        return baseMapper.selectOne(new LambdaQueryWrapper<Dept>().eq(Dept::getName, deptName));
    }

    @Override
    public PageResult<DeptInfoDto> deptSelectPage(DeptSelectPageReq queryReq) {
        IPage<DeptInfoDto> mpPage = MyBatisUtils.buildPage(queryReq);
        mpPage = baseMapper.selectInfoDtoPage(mpPage, queryReq);
        return new PageResult<>(mpPage);
    }

    @Override
    public List<DeptInfoDto> getDeptDtoList(List<Long> deptIdList) {
        if (CollectionUtils.isEmpty(deptIdList)){
            return Collections.emptyList();
        }
        List<Dept> deptList = baseMapper.selectList(new LambdaQueryWrapper<Dept>().in(Dept::getId, deptIdList));
        return deptList.stream().map(dept -> CglibBeanCopierUtil.copy(dept, DeptInfoDto.class)).collect(Collectors.toList());
    }
}
